/**
 * 1、Promise 就是一个类 在执行这个类的时候 需要传递一个执行器进去 执行器会立即执行
 * 2、Promise 中有三种状态 分别为 成功fulfilled 失败  等待 pending
 *  pending -> fulfilled
 *  pending -> rejected
 *  一旦状态确定就不可更改
 * 3、resolve和reject函数是用来更改状态的
 *  resolve: fulfilled
 *  reject: rejected
 * 4、then方法内部做的事情就是判断状态， 如果状态是成功 调用成功的回调函数 如果状态是失败 调用失败的回掉函数 then方法是被定义在原型对象当中
 * 5、then成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因
 * 6、同一个promise对象下面的then方法是可以被调用多次的
 * 7、then方法是可以被链式调用的，后面then方法的回调函数拿到的值是上一个then方法的回调函数的返回值
 */
let promise = new Promise((resolve,reject)=>{
    resolve('成功');
    reject('失败');
});

const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

 class MyPromise {
     constructor(executor){
         try {
            executor(this.resolve,this.reject)
         } catch (e) {
             this.reject(e)
         }
         
     }
     // promise状态
     status = PENDING;
     //成功之后的值
     value = undefined;
     //失败后的原因
     reason = undefined;
     //成功的回调
     successCallback = [];
     //失败的回调
     failCallback = [];
     resolve = (value) =>{
         //如果不是pending状态，则阻止向下执行
         if(this.status!==PENDING)return;
         //将状态更改为成功
         this.status = FULFILLED;
         //保存成功之后的值
         this.value = value;
         //判断成功回调是否存在 如果存在 调用
        //  this.successCallback && this.successCallback(this.value)
         while(this.successCallback.length)this.successCallback.shift()()
     }
     reject = (reason) =>{
        //如果不是pending状态，则阻止向下执行
        if(this.status!==PENDING)return;
        //将状态更改为失败
        this.status = REJECTED;
        //保存失败后的原因
        this.reason = reason;
        //判断失败回调是否存在 如果存在 调用
        // this.failCallback && this.failCallback(this.reason)
        while(this.failCallback.length)this.failCallback.shift()()
     }
     then(successCallback,failCallback){
        successCallback = successCallback ? successCallback : value=>value;
        failCallback = failCallback ? failCallback : reason=>{throw reason};
         let promise2 = new MyPromise((resolve,reject)=>{
             //判断状态
            if(this.status === FULFILLED){
                setTimeout(()=>{
                    try {
                        let x = successCallback(this.value);
                        //判断 x 的值是普通值还是promise对象
                        //如果是普通值 直接调用resolve
                        //如果是promise对象查看promise对象返回的结果
                        //再根据promise对象返回的结果 决定调用resolve 还是调用reject
                        resolvePromise(promise2,x,resolve,reject)
                    } catch (e) {
                        reject(e);
                    }
                },0);
            }else if(this.status === REJECTED){
                setTimeout(()=>{
                    try {
                        let x = failCallback(this.reason);;
                        //判断 x 的值是普通值还是promise对象
                        //如果是普通值 直接调用resolve
                        //如果是promise对象查看promise对象返回的结果
                        //再根据promise对象返回的结果 决定调用resolve 还是调用reject
                        resolvePromise(promise2,x,resolve,reject)
                    } catch (e) {
                        reject(e);
                    }
                },0);
                
            }else{
                //等待
                //将成功回调和失败回调存储起来
                this.successCallback.push(()=>{
                    setTimeout(()=>{
                        try {
                            let x = successCallback(this.value);
                            //判断 x 的值是普通值还是promise对象
                            //如果是普通值 直接调用resolve
                            //如果是promise对象查看promise对象返回的结果
                            //再根据promise对象返回的结果 决定调用resolve 还是调用reject
                            resolvePromise(promise2,x,resolve,reject)
                        } catch (e) {
                            reject(e);
                        }
                    },0);
                });
                this.failCallback.push(()=>{
                    setTimeout(()=>{
                        try {
                            let x = failCallback(this.reason);;
                            //判断 x 的值是普通值还是promise对象
                            //如果是普通值 直接调用resolve
                            //如果是promise对象查看promise对象返回的结果
                            //再根据promise对象返回的结果 决定调用resolve 还是调用reject
                            resolvePromise(promise2,x,resolve,reject)
                        } catch (e) {
                            reject(e);
                        }
                    },0);
                });
            }
         });
         return promise2;
     }
     finally(callback){
         this.then(value=>{
             //要在callback结束之后才进行值的返回操作
             return MyPromise.resolve(callback()).then(()=>value);
         },reason=>{
            return MyPromise.resolve(callback()).then(()=>throw reason);
         });
     }
     catch(failCallback){
         return this.then(undefined,failCallback);
     }
     //所有成功，它才成功，如果有一个失败，则返回失败
     static all (array){
         let result = [];
         let index = 0;
         
         return new MyPromise((resolve,reject)=>{
            function addData(key, value){
                result[key] = value;
                index++;
                //属于技巧，解决for循环内部存在异步操作的问题
                if(index===array.length){
                   resolve(result);
                }
            }
             for(let i=0;i<array.length;i++){
                 let current = array[i];
                 if(current instanceof MyPromise){
                     //promise对象
                     current.then(value => addData(i,value),reason => reject(reason))
                 }else{
                     //普通值
                     addData(i,array[i])
                 }
             }
             
         });
     }
     //把给定的值转换为promise对象
     static resolve(value){
         if(value instanceof MyPromise)return value;
         new MyPromise(resolve => resolve(value))
     }
 }
 function resolvePromise(promise2,x,resolve, reject){
     if(promise2===x){
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'));
     }
     if(x instanceof MyPromise){
         //x.then(value=>resolve(value),reason =>reject(reason))
         x.then(resolve,reject);
     }else{
         //普通值
        resolve(x);
     }
 }

 module.exports = MyPromise